#Anaconda/envs/pyqtenv python
# -*- coding: utf-8 -*-

'''
scave_net_sys_perf_env_resource.py
==================================

.. module:: scave_net_sys_perf_env_resource
  :platform: Windows
  :synopsis: 该模块用于解析 NetOrchestra 仿真器输出的 MANO 求解器输出的日志数据, 并绘制不同网络环境资源量下系统部署时的各求解器的性能情况.

.. moduleauthor:: WangXi

简介
----

该模块实现了从 NetOrchestra 仿真器输出的 MANO 数据中解析不同网络环境资源量下系统部署时的各求解器的性能情况, 主要用于网络编排和虚拟网络功能 VNF 部署的研究与分析中. 
它提供了以下特性:

- 解析 CSV 文件以获取系统运行过程日志.
- 使用 matplotlib 库绘制求解器性能随时间变化的图表.
- 支持多种绘图样式（如线条样式、标记样式等）.

版本
----

- 版本 1.0 (2025/11/19): 初始版本

'''

import os
import copy
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from astropy import units as u
from netorchestr.common.util import DataAnalysis

# region 定义风格
from netorchestr.scave import STYLE_DRAW
color_Bar = STYLE_DRAW.COLOUR_BAR_4
linestyle_Bar = STYLE_DRAW.LINESTYLE_BAR
marker_Bar = STYLE_DRAW.MARKER_BAR

# region 获取数据
from netorchestr.scave import DATA_GROUP
init_time = DATA_GROUP.TIME_SIM_START
data = DATA_GROUP.DATA_ENV_RES_PERF

def __get_array_from_file(filepath:str, watch_item:str):
    data = pd.read_csv(filepath)
    dataFrame = np.array(copy.deepcopy(data[['Time',watch_item]]))
    dataFrame_dict = {}
    for i in range(len(dataFrame)):
        if i == 0:
            dataFrame_dict[init_time + (4.0 * u.hour)] = 0
            continue
        
        time_ms = dataFrame[i][0] * u.ms
        time_real = init_time + time_ms
        
        # 计算系统收益支出比
        watch_value = float(dataFrame[i][1])
        
        dataFrame_dict[time_real] = watch_value
    
    return dataFrame_dict


algo_list = sorted(set([algo_name.split('_')[0] for algo_name in list(data.keys())]))
watch_items = ['SysRevCostRatio', 'SysRev', 'SysCost']
resource_list = np.arange(0.5, 3.5, 0.5)

for algo in data.keys():
    for item in watch_items:
        data[algo][item] = __get_array_from_file(data[algo]['filepath'], watch_item=item)

# region 开始绘图

title ='Solver Performance under Different Network Resource Conditions'

wspace=0.3
hspace=0.3
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=((5+wspace)*3, (5+hspace)*2), sharex=False)
# fig.suptitle(title, y=1.2)
fig.subplots_adjust(wspace=wspace,hspace=hspace)

bar_width = 0.1                                                  # bar宽度
bar_per_group = int(len(data.keys())/len(resource_list))         # 每组bar数量
group_num = len(resource_list)                                   # 总分组数
intra_group_gap = 0.01                                           # 组内间距
inter_group_gap = 0.3                                            # 组间间距

index_array = []
for group_idx in range(group_num):
    # 计算当前组的基准位置
    group_base = group_idx * (bar_per_group * (bar_width + intra_group_gap) + inter_group_gap)
    # 计算组内每个bar的索引
    for bar_idx in range(bar_per_group):
        bar_pos = group_base + bar_idx * (bar_width + intra_group_gap)
        index_array.append(bar_pos)
        
index_2d = []
for bar_idx in range(bar_per_group):
    bar_positions = index_array[bar_idx::bar_per_group]
    index_2d.append(bar_positions)
    
group_centers = []
for group_idx in range(group_num):
    # 每组第一个bar的位置 + 每组最后一个bar的位置 → 除以2得中心
    group_first_bar = group_idx * (bar_per_group * (bar_width + intra_group_gap) + inter_group_gap)
    group_last_bar = group_first_bar + (bar_per_group - 1) * (bar_width + intra_group_gap)
    group_center = (group_first_bar + group_last_bar) / 2
    group_centers.append(group_center)

for ax_index, ax in enumerate(axes[0]):
    ax.set(xlabel='Environment Resource', ylabel=watch_items[ax_index])
    item = watch_items[ax_index]
    
    for i,algo in enumerate(algo_list):
        y_value = []
        for res_value in resource_list:
            y_value.append(np.array(list(data[algo+'_'+str(res_value)][item].values()))[-1])

        ax.bar(index_2d[i],
               height=y_value,
               label=algo,
               color=color_Bar[i % len(color_Bar)],
               width=bar_width,
               edgecolor='black',
               linewidth=0.5)

    ax.set_xticks(group_centers)  # 刻度位置
    ax.set_xticklabels(resource_list)  # 刻度标签
    ax.tick_params(axis='x', rotation=0)

    ax.grid(True, linestyle='--', alpha=0.6)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.legend(frameon=False, loc='lower center', ncol=3, bbox_to_anchor=(0.5, 1))

watch_items = ['sfcSetNum', 'sfcCompleteNum', 'sfcCompleteRate', 'sfcSetRate']
for ax_index, ax in enumerate(axes[1]):
    ax.set(xlabel='Environment Resource', ylabel=watch_items[ax_index])
    item = watch_items[ax_index]
    
    for i,algo in enumerate(algo_list):
        y_value = []
        for res_value in resource_list:
            y_value.append(DataAnalysis.getResult(data[algo+'_'+str(res_value)]['filepath'], print_flag=False, draw_flag=False)[item])

        ax.bar(index_2d[i],
               height=y_value,
               label=algo,
               color=color_Bar[i % len(color_Bar)],
               width=bar_width,
               edgecolor='black',
               linewidth=0.5)

    ax.set_xticks(group_centers)  # 刻度位置
    ax.set_xticklabels(resource_list)  # 刻度标签
    ax.tick_params(axis='x', rotation=0)

    ax.grid(True, linestyle='--', alpha=0.6)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.legend(frameon=False, loc='lower center', ncol=3, bbox_to_anchor=(0.5, 1))

if not os.path.exists('fig'):
    os.makedirs('fig')

fig.savefig('fig/'+title.replace(' ','_')+'.svg',format='svg',dpi=150)
fig.savefig('fig/'+title.replace(' ','_')+'.pdf', bbox_inches='tight', pad_inches=0.5)
